(function (definition) {
    // RequireJS
    if (typeof define == "function") {
        define(definition);
    } else {
        definition();
    }
})(function() {
	window.Asdf = {};
});(function($_) {
	$_.O = {};
	var ObjProto = Object.prototype, ArrayProto = Array.prototype, 
	_toString = ObjProto.toString, NULL_TYPE = 'Null', 
	UNDEFINED_TYPE = 'Undefined', BOOLEAN_TYPE = 'Boolean', 
	NUMBER_TYPE = 'Number', STRING_TYPE = 'String', 
	OBJECT_TYPE = 'Object', FUNCTION_CLASS = '[object Function]', 
	BOOLEAN_CLASS = '[object Boolean]', NUMBER_CLASS = '[object Number]', 
	STRING_CLASS = '[object String]', ARRAY_CLASS = '[object Array]', 
	DATE_CLASS = '[object Date]', REGEXP_CLASS = '[object RegExp]',
	ARGUMENTS_CLASS = '[object Arguments]',
	hasOwnProperty = ObjProto.hasOwnProperty, slice = ArrayProto.slice ;

	function extend() {
		var destination , source , defaults, deep = false, arg = slice.call(arguments), clone, src;
		destination = arg.shift();
		if(typeof destination === "boolean"){
			deep = destination;
			destination = arg.shift();
		}
		source = arg.shift();
		defaults = !!arg.shift();
		for (var property in source){
			if(hasOwnProperty.call(source,property)  && !(destination[property] && defaults)){
				src = destination[property];
				if(deep && (isArray(source[property])||isPlainObject(source[property]))){
					if(isArray(source[property])){
						clone = src && isArray(src)? src : [];
					} else if(isPlainObject(source[property])){
						clone = src? src : {};
					}
					destination[property] = extend(deep, clone, source[property]);
				} else {
					destination[property] = source[property];
				}
			}
		}
		return destination;
	}
	function isPlainObject(object) {
		if(!object || !isObject(object) || object.nodeType || object === object.window) {
			return false;
		}
		try{
			if (object.constructor &&
				!hasOwnProperty.call(object, "constructor") &&
				!hasOwnProperty.call(object.constructor.prototype, "isPrototypeOf") ) {
				return false;
			}
		}catch (e) {
			return false;
		}
		var key;
		for( key in object ){}
		return key === undefined || hasOwnProperty.call(object, key);
	}
	
	function isElement(object) {
		return !!(object && object.nodeType == 1);
	}

	function isArray(object) {
		var hasNativeIsArray = (typeof Array.isArray == 'function') && Array.isArray([]) && !Array.isArray({});
		if (hasNativeIsArray) {
			isArray = Array.isArray;
			return Array.isArray(object);
		}
		return _toString.call(object) === ARRAY_CLASS;
	}
	function isObject(object) {
		return object === Object(object);
	}
	function isArguments(object) {
		return _toString.call(object) === ARGUMENTS_CLASS;
	}
	function isFunction(object) {
		return _toString.call(object) === FUNCTION_CLASS;
	}

	function isString(object) {
		return _toString.call(object) === STRING_CLASS;
	}

	function isNumber(object) {
		return _toString.call(object) === NUMBER_CLASS;
	}

	function isDate(object) {
		return _toString.call(object) === DATE_CLASS;
	}
	
	function isRegexp(object) {
		return _toString.call(object) === REGEXP_CLASS;
	}

	function isUndefined(object) {
		return typeof object === "undefined";
	}
	function keys(object) {
		if ((typeof object != "object" && typeof object != "function")
				|| object === null) {
			throw new TypeError("Object.key called on a non-object");
		}
		var keys = [];
		for ( var name in object) {
			if ({}.hasOwnProperty.call(object, name)) {
				keys.push(name);
			}
		}
		return keys;
	}
	
	function values(object) {
		if ((typeof object != "object" && typeof object != "function")
				|| object === null) {
			throw new TypeError("Object.values called on a non-object");
		}
		var values = [];
		for ( var name in object) {
			if ({}.hasOwnProperty.call(object, name)) {
				values.push(object[name]);
			}
		}
		return values;
	}
	function functions(obj) {
		var names = [];
		for ( var key in obj) {
			if (isFunction(obj[key]))
				names.push(key);
		}
		return names.sort();
	}
	
	
	function pick(obj) {
		var result = {};
		slice.call(arguments).flatten().forEach(function(key) {
			if (key in obj)
				result[key] = obj[key];
		});
		return result;
	}
	function clone(obj) {
		if (!isObject(obj))
			return obj;
		return isArray(obj) ? obj.slice() : extend(true, {}, obj);
	}
	function toQueryString(obj) {
		function toQueryPair(key, value) {
			key = encodeURIComponent(key);
			if (isUndefined(value))
				return key;
			return key + '=' + encodeURIComponent(value);
		}
		var res = [];
		for (name in obj){
			if (hasOwnProperty.call(obj, name)){
				var values = obj[name];
				if(isArray(values)){
					var queryValues = [];
					for(var i = 0; i < values.length; i++){
						queryValues.push(toQueryPair(name, values[i]));
					}
					res = res.concat(queryValues);
				}else {
					res.push(toQueryPair(name, values));
				}
			}
		}
		return res.join('&');
	}
	extend($_.O, {
		extend: extend,
		keys: keys,
		values : values,
		functions : functions,
		isElement : isElement,
		isArray : isArray,
		isObject: isObject,
		isPlainObject: isPlainObject,
		isArguments: isArguments,
		isFunction : isFunction,
		isString : isString,
		isNumber : isNumber,
		isDate : isDate,
		isRegexp: isRegexp,
		isUndefined : isUndefined,
		pick: pick,
		clone: clone,
		toQueryString: toQueryString
	});
})(Asdf);
(function($_) {
	$_.F = {};
	var slice = Array.prototype.slice, fnProto = Function.prototype, nativeBind = fnProto.bind;
	function identity(value) {
		return value;
	}
	function update(array, args) {
		var arrayLength = array.length, length = args.length;
		while (length--)
			array[arrayLength + length] = args[length];
		return array;
	}
	function merge(array, args) {
		array = slice.call(array, 0);
		return update(array, args);
	}
	function bind(func, context) {
		if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
		if (!$_.O.isFunction(func)) throw new TypeError;
		if (arguments.length < 3 && $_.O.isUndefined(arguments[1])) return func;
		var __method = func, args = slice.call(arguments, 2);
		return function() {
			var a = merge(args, arguments);
			return __method.apply(context, a);
		};
	}
	function curry(func) {
		if (!$_.O.isFunction(func)) throw new TypeError;
		if (!arguments.length)
			return func;
		var __method = func, args = slice.call(arguments, 1);
		return function() {
			var a = merge(args, arguments);
			return __method.apply(this, a);
		};
	}

	function delay(func, timeout) {
		if (!$_.O.isFunction(func)) throw new TypeError;
		var __method = func, args = slice.call(arguments, 2);
		timeout = timeout * 1000;
		return window.setTimeout(function() {
			return __method.apply(__method, args);
		}, timeout);
	}
	function defer(func) {
		if (!$_.O.isFunction(func)) throw new TypeError;
		var args = update([ 0.01 ], slice.call(arguments, 1));
		return delay(func, args);
	}

	function wrap(func, wrapper) {
		if (!$_.O.isFunction(func)) throw new TypeError;
		var __method = func;
		return function() {
			var a = update([ bind(__method, this) ], arguments);
			return wrapper.apply(this, a);
		};
	}
	function methodize(func) {
		if (func._methodized)
			return func._methodized;
		var __method = func;
		return func._methodized = function() {
			var a = update([ this ], slice.call(arguments,0));
			return __method.apply(null, a);
		};
	}
	
	$_.O.extend($_.F, {
		identity: identity,
		bind: bind,
		curry: curry,
		delay: delay,
		defer: defer,
		wrap: wrap,
		methodize: methodize
	}, true);

})(Asdf);(function($_) {
	$_.A = {};
	var hasOwnProperty = Object.prototype.hasOwnProperty, arrayProto = Array.prototype, slice = arrayProto.slice, nativeForEach = arrayProto.forEach, nativeMap = arrayProto.map, nativeReduce = arrayProto.reduce, nativeReduceRight = arrayProto.reduceRight, nativeFilter = arrayProto.filter, nativeEvery = arrayProto.every, nativeSome = arrayProto.some, nativeIndexOf = arrayProto.indexOf, nativeLastIndexOf = arrayProto.lastIndexOf, nativeIsArray = Array.isArray;
	var breaker = {};
	function each(obj, iterator, context) {
		if (obj == null)
			return;
		if (nativeForEach && obj.forEach === nativeForEach) {
			obj.forEach(iterator, context);
		} else if (obj.length === +obj.length) {
			for ( var i = 0, l = obj.length; i < l; i++) {
				if (i in obj
						&& iterator.call(context, obj[i], i, obj) === breaker)
					return;
			}
		} else {
			for ( var key in obj) {
				if (hasOwnProperty.call(obj, key)) {
					if (iterator.call(context, obj[key], key, obj) === breaker)
						return;
				}
			}
		}
	}
	function map(obj, iterator, context) {
		
		var results = [];
		if (obj == null)
			return results;
		if (nativeMap && obj.map === nativeMap)
			return obj.map(iterator, context);
		each(obj, function(value, index, list) {
			results[results.length] = iterator.call(context, value, index, list);
		});
		if (obj.length === +obj.length)
			results.length = obj.length;
		return results;
	}
	function reduce(obj, iterator, memo, context) {
		var initial = arguments.length > 2;
		if (obj == null)
			obj = [];
		if (nativeReduce && obj.reduce === nativeReduce) {
			if (context)
				iterator = $_.F.bind(iterator, context);
			return initial ? obj.reduce(iterator, memo) : obj
					.reduce(iterator);
		}
		each(obj,
				function(value, index, list) {
					if (!initial) {
						memo = value;
						initial = true;
					} else {
						memo = iterator.call(context, memo, value,
								index, list);
					}
				});
		if (!initial)
			throw new TypeError(
					'Reduce of empty array with no initial value');
		return memo;
	}
	function reduceRight(obj, iterator, memo, context) {
		var initial = arguments.length > 2;
		if (obj == null)
			obj = [];
		if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
			if (context)
				iterator = $_.F.bind(iterator, context);
			return initial ? obj.reduceRight(iterator, memo) : obj
					.reduceRight(iterator);
		}
		var reversed = toArray(obj).reverse();
		if (context && !initial)
			iterator = $_.F.bind(iterator, context);
		return initial ? reduce(reversed, iterator, memo, context)
				: reduce(reversed, iterator);
	}
	function first(array, n, guard) {
		return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
	}
	function last(array, n, guard) {
		if ((n != null) && !guard) {
			return slice.call(array, Math.max(array.length - n, 0));
		} else {
			return array[array.length - 1];
		}
	}
	function filter(obj, iterator, context) {
		var results = [];
		if (obj == null)
			return results;
		if (nativeFilter && obj.filter === nativeFilter)
			return obj.filter(iterator, context);
		each(obj, function(value, index, list) {
			if (iterator.call(context, value, index, list))
				results[results.length] = value;
		});
		return results;
	}
	function reject(obj, iterator, context) {
		var results = [];
		if (obj == null)
			return results;
		each(obj, function(value, index, list) {
			if (!iterator.call(context, value, index, list))
				results[results.length] = value;
		});
		return results;
	}
	function every(obj, iterator, context) {
	    var result = true;
		if (obj == null)
			return result;
		if (nativeEvery && obj.every === nativeEvery)
			return obj.every(iterator, context);
		each(obj, function(value, index, list) {
			if (!(result = result
					&& iterator.call(context, value, index, list)))
				return breaker;
		});
		return !!result;
	}
	function any(obj, iterator, context) {
		iterator || (iterator = _.identity);
		var result = false;
		if (obj == null)
			return result;
		if (nativeSome && obj.some === nativeSome)
			return obj.some(iterator, context);
		each(obj, function(value, index, list) {
			if (result
					|| (result = iterator.call(context, value, index,
							list)))
				return breaker;
		});
		return !!result;
	}
	function include(obj, target) {
		var found = false;
		if (obj == null)
			return found;
		if (nativeIndexOf && obj.indexOf === nativeIndexOf)
			return obj.indexOf(target) != -1;
		found = any(obj, function(value) {
			return value === target;
		});
		return found;
	}
	function invoke(obj, method) {
		var args = slice.call(arguments, 2);
		return map(obj, function(value) {
			return ($_.F.isFunction(method) ? method || value
					: value[method]).apply(value, args);
		});
	}
	function pluck(obj, key) {
		return map(obj, function(value){ return value[key]; });
	}
	function max(obj, iterator, context) {
		if (!iterator && $_.O.isArray(obj) && obj[0] === +obj[0])
			return Math.max.apply(Math, obj);
		if (!iterator && $_.O.isEmpty(obj))
			return -Infinity;
		var result = {
			computed : -Infinity
		};
		each(obj, function(value, index, list) {
			var computed = iterator ? iterator.call(context, value,
					index, list) : value;
			computed >= result.computed && (result = {
				value : value,
				computed : computed
			});
		});
		return result.value;
	}
	function min(obj, iterator, context) {
		if (!iterator && $_.O.isArray(obj) && obj[0] === +obj[0])
			return Math.min.apply(Math, obj);
		if (!iterator && $_.O.isEmpty(obj))
			return Infinity;
		var result = {
			computed : Infinity
		};
		each(obj, function(value, index, list) {
			var computed = iterator ? iterator.call(context, value,
					index, list) : value;
			computed < result.computed && (result = {
				value : value,
				computed : computed
			});
		});
		return result.value;
	}
	function shuffle(obj) {
		var shuffled = [], rand;
		each(obj, function(value, index, list) {
			rand = Math.floor(Math.random() * (index + 1));
			shuffled[index] = shuffled[rand];
			shuffled[rand] = value;
		});
		return shuffled;
	}
	function sortBy(obj, val, context) {
		var iterator = $_.O.isFunction(val) ? val : function(obj) {
			return obj[val];
		};
		return pluck(map(obj, function(value, index, list) {
			return {
				value : value,
				criteria : iterator.call(context, value, index, list)
			};
		}).sort(function(left, right) {
			var a = left.criteria, b = right.criteria;
			if (a === void 0)
				return 1;
			if (b === void 0)
				return -1;
			return a < b ? -1 : a > b ? 1 : 0;
		}), 'value');
	}
	function groupBy(obj,val) {
		var result = {};
		var iterator = $_.O.isFunction(val) ? val : function(obj) {
			return obj[val];
		};
		each(obj, function(value, index) {
			var key = iterator(value, index);
			(result[key] || (result[key] = [])).push(value);
		});
		return result;
	}
	function sortedIndex(array, obj, iterator) {
		iterator || (iterator = $_.F.identity);
		var low = 0, high = array.length;
		while (low < high) {
			var mid = (low + high) >> 1;
			iterator(array[mid]) < iterator(obj) ? low = mid + 1
					: high = mid;
		}
		return low;
	}
	
	function toArray(obj) {
		if (!obj)
			return [];
		if ($_.O.isArray(obj))
			return slice.call(obj);
		if ($_.O.isArguments(obj))
			return slice.call(obj);
		if (obj.toArray && $_.O.isFunction(obj.toArray))
			return obj.toArray();
		return $_.O.values(obj);
	}
	function size(obj) {
		return $_.O.isArray(obj) ? obj.length : keys(obj).length;
	}
	
	function clear(array) {
		array.length = 0;
		return array;
	}
	function initial(array, n, guard) {
		return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
	}
	function rest(array, index, guard) {
		return slice.call(array, (index == null) || guard ? 1 : index);
	}
	function compact(array) {
		return filter(array, function(value){ return !!value; });
	}
	function flatten(array, shallow) {
		return reduce(array, function(memo, value) {
		      if ($_.O.isArray(value)) return memo.concat(shallow ? value : flatten(value));
		      memo[memo.length] = value;
		      return memo;
		    }, []);
	}
	function without(array) {
		return difference(array, slice.call(arguments, 1));
	}
	function unique(array, isSorted, iterator) {
		var initial = iterator ? map(array, iterator) : array;
		var results = [];
		// The `isSorted` flag is irrelevant if the array only contains
		// two elements.
		if (array.length < 3)
			isSorted = true;
		reduce(initial, function(memo, value, index) {
			if (isSorted ? last(memo) !== value || !memo.length
					: !include(memo, value)) {
				memo.push(value);
				results.push(array[index]);
			}
			return memo;
		}, []);
		return results;
	}
	function union() {
		 return unique(flatten(arguments, true));
	}
	function intersection(array) {
		var rest = slice.call(arguments, 1);
		return filter(unique(array), function(item) {
			return every(rest, function(other) {
				return indexOf(other, item) >= 0;
			});
		});
	}
	function difference(array) {
		var rest = flatten(slice.call(arguments, 1), true);
	    return filter(array, function(value){ return !include(rest, value); });
	}
	function zip() {
		var args = slice.call(arguments);
	    var length = max(pluck(args, 'length'));
	    var results = new Array(length);
	    for (var i = 0; i < length; i++) results[i] = pluck(args, "" + i);
	    return results;
	}
	function indexOf(array, item, isSorted) {
		if (array == null) return -1;
	    var i, l;
	    if (isSorted) {
	      i = sortedIndex(array, item);
	      return array[i] === item ? i : -1;
	    }
	    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
	    for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
	    return -1;
	}
	function lastIndexOf(array, item) {
		if (array == null) return -1;
	    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
	    var i = array.length;
	    while (i--) if (i in array && array[i] === item) return i;
	    return -1;
	}
	function range (start, stop, step) {
		if (arguments.length <= 1) {
		      stop = start || 0;
		      start = 0;
		}
		step = arguments[2] || 1;
		var len = Math.max(Math.ceil((stop - start) / step), 0);
		var idx = 0;
		var range = new Array(len);
		while(idx < len) {
			range[idx++] = start;
		    start += step;
		}
		return range;
	}
	function inject(array, memo, iterator, context) {
		each(array, function(value, index) {
			memo = iterator.call(context, memo, value, index);
		});
		return memo;
	}
	$_.O.extend($_.A, {
		each: each,
		map: map,
		reduce: reduce,
		reduceRight: reduceRight,
		first: first,
		last: last,
		filter: filter,
		reject: reject,
		every: every,
		any: any,
		include: include,
		invoke: invoke,
		pluck: pluck,
		max: max,
		min: min,
		shuffle: shuffle,
		sortBy: sortBy,
		groupBy: groupBy,
		sortedIndex: sortedIndex,
		toArray: toArray,
		size: size,
		clear: clear,
		initial: initial,
		rest: rest,
		compact: compact,
		flatten: flatten,
		without: without,
		unique: unique,
		union: union,
		intersection: intersection,
		difference: difference,
		zip: zip,
		indexOf: indexOf,
		lastIndexOf: lastIndexOf,
		range: range,
		inject: inject
	}, true);
})(Asdf);(function($_) {
	$_.S = {};
	function truncate(str, length, truncation) {
		length = length || 30;
		truncation = Object.isUndefined(truncation) ? '...' : truncation;
		return str.length > length ?
		this.slice(0, length - truncation.length) + truncation : String(str);
	}
	function trim(str) {
		return str.replace(/^\s+/, '').replace(/\s+$/, '');
	}
	function stripTags(str) {
	    return str.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
	}
	function escapeHTML(str) {
	    return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
	}
	function unescapeHTML(str) {
	    return str.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
	}
	function toQueryParams(str,separator) {
		var inject = $_.A.inject;
		var match = trim(str).match(/([^?#]*)(#.*)?$/);
		if (!match)
			return {};
		return inject(match[1].split(separator || '&'),	{}, function(hash, pair) {
			if ((pair = pair.split('='))[0]) {
				var key = decodeURIComponent(pair.shift()), value = pair.length > 1 ? pair.join('='): pair[0];
				if (value != undefined)
					value = decodeURIComponent(value);
				if (key in hash) {
					if (!Array.isArray(hash[key])){
						hash[key] = [ hash[key] ];
					}
					hash[key].push(value);
				} else
					hash[key] = value;
				}
			return hash;
		});
	}
	function toArray(str) {
	    return str.split('');
	}
	function succ(str) {
	    return str.slice(0, this.length - 1) +
	      String.fromCharCode(this.charCodeAt(str.length - 1) + 1);
	}
	function times(str, count) {
	    return count < 1 ? '' : new Array(count + 1).join(str);
	}
	function camelize(str) {
	    return str.replace(/-+(.)?/g, function(match, chr) {
	      return chr ? chr.toUpperCase() : '';
	    });
	}
	function capitalize(str) {
	    return str.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
	}
	function underscore(str) {
	    return str.replace(/::/g, '/')
	               .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
	               .replace(/([a-z\d])([A-Z])/g, '$1_$2')
	               .replace(/-/g, '_')
	               .toLowerCase();
	}
	function dasherize(str) {
	    return str.replace(/_/g, '-');
	}
	function include(str, pattern) {
	    return str.indexOf(pattern) > -1;
	}
	function startsWith(str, pattern) {
	    return str.lastIndexOf(pattern, 0) === 0;
	}
	function endsWith(str, pattern) {
	    var d = str.length - pattern.length;
	    return d >= 0 && str.indexOf(pattern, d) === d;
	}
	function empty(str) {
	    return this == '';
	}
	function blank(str) {
	    return /^\s*$/.test(str);
	}
	function toDocumentFragment(str) {
		var el = document.createElement('div'), frg = document.createDocumentFragment();
		el.innerHTML = str;
		while(el.childNodes.length) frg.appendChild(el.childNodes[0]);
		return frg;	
	}
	$_.O.extend($_.S, {
		truncate: truncate,
		trim: trim,
		stripTags: stripTags,
		escapeHTML: escapeHTML,
		unescapeHTML: unescapeHTML,
		toQueryParams: toQueryParams,
		toArray: toArray,
		succ: succ,
		times: times,
		camelize: camelize,
		capitalize: capitalize,
		underscore: underscore,
		dasherize: dasherize,
		include: include,
		startsWith: startsWith,
		endsWith: endsWith,
		empty: empty,
		blank: blank,
		toDocumentFragment:toDocumentFragment
	});
})(Asdf);
(function($_) {
	$_.Event = {};
	var extend = $_.O.extend, slice = Array.prototype.slice;
	cach = [];
	function getIndex(element, eventName, handler) {
		var i;
		for(i = 0; i < cach.length; i++){
			if(cach[i].element == element &&
					cach[i].eventName == eventName &&
					cach[i].handler == handler)
				return i;
		}
		return -1;
	}
	function getWrapedhandler(element, eventName, handler) {
		var i;
		for(i = 0; i < cach.length; i++){
			if(cach[i].element == element &&
					cach[i].eventName == eventName &&
					cach[i].handler == handler)
				return cach[i].wrapedhandler.pop();
		}
	}
	function addEventListener(element, eventName, handler) {
		wrapedhandler = $_.F.wrap(handler, 
			function(ofn, e) {
				e = e||window.event;
				e = fix(e);
				return ofn(e);
			}
		);
		if (element.addEventListener) {
			element.addEventListener(eventName, wrapedhandler, false);
			
		}else {
			element.attachEvent("on"+ eventName, wrapedhandler);
		}
		var index = getIndex(element, eventName, handler);
		if(index === -1){
			var obj = {element:element, eventName:eventName, handler:handler, wrapedhandler:[wrapedhandler]};
			cach.push(obj);
		}else{
			cach[index].wrapedhandler.push(wrapedhandler);
		}
		
	}
	function removeEventListener(element, eventName, handler){
		wrapedhandler = getWrapedhandler(element, eventName, handler)||handler;
		if(element.removeEventListener){
			element.removeEventListener( eventName, wrapedhandler, false );
		}else {
			var ieeventName = 'on'+eventName;
			if(element[ieeventName] === void 0){
				element[ieeventName] = null;
			}
			element.detachEvent( ieeventName, wrapedhandler );
		}
		
	}
	function fix(event){
		if(!event.target){
			event.target = event.srcElement || document;
		}
		if(event.target.nodeType === 3) {
			event.target = event.target.parentNode;
		}
		event.metaKey = !!event.metaKey;
		return fixHooks(event);
	}
	function stop(event){
		if(!event.stopPropagation) {
			event.stopPropagation = function() { this.cancelBubble = true; };
			event.preventDefault = function() { this.returnValue = false; };
		}
		event.preventDefault();
	    event.stopPropagation();
	}
	function fixHooks(event){
		function keyHooks(event){
			if(event.which === null) {
				event.which = event.charCode !== null ? event.charCode : event.keyCode;
			}
			return event;
		}
		function mouseHooks(event){
			var eventDoc, doc, body, button = event.button, fromElement = event.fromElement;
			if( event.pageX == null && event.clientX != null ) {
				eventDoc = event.target.ownderDocument || document;
				doc = eventDoc.documentElement;
				body = eventDoc.body;
				event.pageX = event.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
				event.pageY = event.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
			}
			if ( !event.relatedTarget && fromElement ) {
				event.relatedTarget = fromElement === event.target ? event.toElement : fromElement;
			}
			if ( !event.which && button !== undefined ) {
				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
			}
			return event;
		}
		var rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|contextmenu)|click/ ;
		if ( rkeyEvent.test( event.type ) ) {
			return keyHooks(event);
		}
		if ( rmouseEvent.test( event.type ) ) {
			return mouseHooks(event);
		}
		return event;
	}
	function on(element, eventName, fn, preFn){
		addEventListener(element, eventName, fn);
		return element;
	}
	function once(element, eventName, fn, PreFn){
		var tfn = $_.F.wrap(fn, function(ofn){
			var arg = slice.call(arguments, 1);
			ofn.apply(this,arg);
			remove(element, eventName, tfn);
		});
		addEventListener(element, eventName, tfn);
		return element;
	}
	function remove(element, eventName, fn) {
		removeEventListener(element, eventName, fn);
		return element;
	}
	function removeAll(element, eventName) {
		var events, i;
		events = $_.A.filter(cach, function (val, i) {
			if(element === val.element) {
				if(eventName && eventName !== val.eventName){
					return false;
				}
				return true;
				
			}
		});
		for ( var i = 0; events && i < events.length; i++){
			removeEventListener(events[i].element, events[i].eventName, events[i].handler);
		}
		return element;
	}
	function createEvent(name) {
		var event;
		if(document.createEvent) {
			event = document.createEvent('HTMLEvents');
			event.initEvent(name, true, true);
		}else {
			event = document.createEventObject();
		}
		return event;
		
	}
	function emit(element, name, data){
		if(element == document && document.createEvent && !element.dispatchEvent)
			element = document.documentElement;
		var event;
		
		event = createEvent(name);
		event.data = data;
		event.eventName = name;
		if(document.createEvent) {
			element.dispatchEvent(event);
		}else {
			element.fireEvent("on"+name, event);
		}
		return element;
	}
    extend($_.Event, {
    	fix: fix,
    	stop:stop,
    	on:on,
    	remove:remove,
    	removeAll:removeAll,
    	once: once,
    	emit: emit
    });
})(Asdf);(function (definition) {
    // RequireJS
    if (typeof define == "function") {
        define([Asdf], definition);
    } else {
        definition(Asdf);
    }
})
(function($_) {
	var nativeSlice = Array.prototype.slice, extend = $_.O.extend,
		isElement = $_.O.isElement, isString = $_.O.isString, trim = $_.S.trim;
	$_.Element = {};
	function recursivelyCollect(element, property, until) {
		var elements = [];
		while (element = element[property]) {
			if (element.nodeType == 1)
				elements.push(element);
			if (element == until)
				break;
		}
		return elements;
	}
	function recursively( element, property ) {
		do {
			element = element[ property ];
		} while ( element && element.nodeType !== 1 );
		return element;
	}
	function walk(element, fun, context) {
		context = context || this;
		var i, childNodes = $_.A.toArray(element.childNodes);
		fun.call(context, element);
		for (i = 0; i < childNodes.length ; i++) {
			walk(childNodes[i], fun);
		}
		return element;
	}
	function visible(element){
		return element.style.display !='none';
	}
	function toggle(element) {
	    visible(element) ? hide(element) : show(element);
	    return element;
	}
	function hide(element) {
		element.style.display = 'none';
	    return element;
	}
	function show(element) {
		 element.style.display = '';
		 return element;
	}
	function remove(element) {
		element.parentNode.removeChild(element);
	    return element;
	}
	function text(element, value) {
		var ret = '';
		if( !value ){
			if ( typeof element.textContent === "string" ) {
				return element.textContent;
			} else {
				walk(element, function(e) {
					var nodeType = e.nodeType;
					if( nodeType === 3 || nodeType === 4 ) {
						ret += e.nodeValue;
					}
					return false;
				});
				return ret;
			}
		}else {
			append(empty(element), (element.ownerDocument || document ).createTextNode( value ) );
		}
	}
	function value(element, value) {
		return (!value)? element.value : element.value = value;
	}
	function html(element, html) {
		return (!html)? element.innerHTML: element.innerHTML = html;
	}
	function parent(element){
		return recursively(element, 'parentNode');
	}
	function parents(element, until) {	
		 return recursivelyCollect(element, 'parentNode', until);
	}
	function next(element){
		return recursively(element, 'nextSibling');
	}
	function prev(element){
		return recursively(element, 'previousSibling');
	}
	function nexts(element, until) {
		return recursivelyCollect(element, 'nextSibling', until);
	}
	function prevs(element, until) {
		return recursivelyCollect(element, 'previousSibling', until);
	}
	function siblings(element) {
		return previousSiblings(element).reverse().concat(Element.nextSiblings(element));
	}
	function children(element) {
		return nexts(element.firstChild, 'nextSibling');
	}
	function contents(element) {
		return (element.nodeName === 'IFRAM')?element.contentDocument||element.contentWindow.document : element.childNodes ;
	}
	function wrap(element, newContent) {
		element.parentNode.replaceChild(newContent, element);
		newContent.appendChild(element);
		return newContent;
	}
	function unwrap(element) {
		var bin = document.createDocumentFragment();
		var parentNode = element.parentNode;
		bin.appendChild(element);
		parentNode.parentNode.replaceChild(element, parentNode);
		return element;
	}
	function append(element, newContent) {
		var nodeType = element.nodeType;
		if ( nodeType === 1 || nodeType === 11 ) {
			element.appendChild( newContent );
		}
		return element;
	}
	function prepend(element, newContent) {
		var nodeType = element.nodeType;
		if ( nodeType === 1 || nodeType === 11 ) {
			element.insertBefore( newContent, element.firstChild );
		}
		return element;
	}
	function before(element, newContent) {
		element.parentNode.insertBefore(newContent, element);
		return element;
	}
	function after(element, newContent) {
		element.parentNode.insertBefore(newContent, element.nextSibling);
		return element;		
	}
	function empty(element) {
		element.innerHTML = '';
		return element;
	}
	function remove(element) {
		element.parentNode.removeChild(element);
	}
	function attr(element, name, value) {
		var result, key;
		if(!name || !isString(name)){
			return null;
		}
		if(element.nodeType !== 1){
			return null;
		}
		if(!value){
			if(name === 'value' && element.nodeName === 'INPUT' ){
				return element.value();
			}
			return (!(result = element.getAttribute(name)) && name in element) ? element[name] : result;
		}else {
			if (typeof name === 'object'){
				for (key in name)
					element.setAttribute(key, name[key]);
			}else {
				element.setAttribute(name, value);
			}
			return element;
		}
	}
	function removeAttr(element, name) {
		if(element.nodeType === 1)
			element.removeAttribute(name);
		return element;
	}
	function prop(element, name, value) {
		if(!value){
			return element[name];
		} else {
			element[name] = value;
			return element;
		}
	}
	function removeProp(element, name){
		if(element[name])
			delete element[name];
		return element;
	}
	function offset(element) {
		// IE 경우 document.documentElement.scrollTop 그 외 document.body.scrollTop
		var width = 0,
			height = 0,
			rect = element.getBoundingClientRect(),
			top = rect.top + (document.body.scrollTop || pageYOffset),
			bottom = rect.bottom + (document.body.scrollTop || pageYOffset),
			right = rect.right + (document.body.scrollLeft || window.pageXOffset),
			left = rect.left + (document.body.scrollLeft || window.pageXOffset);
		if (rect.height) {
			height = rect.height;
			width = rect.width;
		} else {
			height = element.offsetHeight || bottom - top;
			width = element.offsetWidth || right - left;
		}
		return {
			height : height,
			width : width,
			top : top,
			bottom : bottom,
			right : right,
			left : left
		};
	};
	function addClass(element, name){
		if(!hasClass(element, name))		
			element.className += (element.className? ' ':'') + name;
		return element;
	};
	function removeClass(element, name) {
		element.className = element.className.replace(new RegExp("^|\\s+)" + name + "(\\s+|$)"), ' ').trim();
		return element;
	}
	function toggleClass(element, name) {
	}
	function hasClass(element, name) {
		return element.className && element.className > 0 && new RegExp("(^|\\s)" + name + "(\\s|$)").test(element.className);
	}
	function find(element, selector, results, seed){
		if(window.Sizzle){
			return Sizzle(selector, element, results);
		}else {
			return $_.A.toArray(querySelectorAll(element, selector)).concat(results);
		}
	}
	function querySelectorAll(element, selctor) {
		if(window.Element&&Element.prototype.querySelectorAll) {
			return Element.prototype.querySelectorAll.apply(element, nativeSlice.call(arguments, 1));
		}else {
			var a=element.all, c=[], selctor = selctor.replace(/\[for\b/gi, '[htmlFor').split(','), i, j,s=document.createStyleSheet();
			for (i=selctor.length; i--;) {
				s.addRule(selctor[i], 'k:v');
				for (j=a.length; j--;) a[j].currentStyle.k && c.push(a[j]);
				s.removeRule(0);
			}
			return c;
		}
	}
	extend($_.Element,  {
		walk: walk,
		visible: visible,
		toggle: toggle,
		hide: hide,
		show: show,
		remove: remove,
		text: text,
		value: value,
		html: html,
		parent: parent,
		parents: parents,
		next: next,
		prev: prev,
		nexts: nexts,
		prevs: prevs,
		siblings: siblings,
		children: children,
		contents: contents,
		wrap: wrap,
		unwrap: unwrap,
		append: append,
		prepend: prepend,
		before: before,
		after: after,
		empty: empty,
		attr: attr,
		removeAttr: removeAttr,
		prop: prop,
		removeProp: removeProp,
		offset: offset,
		addClass: addClass,
		removeClass: removeClass,
		toggleClass: toggleClass,
		hasClass: hasClass,
		find: find,
		querySelectorAll: querySelectorAll
	});
});(function ($_) {
	$_.Utils = {};
	function randomMax8HexChars() {
        return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
	}
	function makeuid () {
		return randomMax8HexChars() + randomMax8HexChars();
	}
	var domReadyfn = [];
	function ready(callback) {
		var timer, defer = $_.F.defer;
		function fireContentLoadedEvent() {
			var i;
			if (document.loaded)
				return;
			if (timer)
				window.clearTimeout(timer);
			document.loaded = true;
			for(i = 0 ; i < domReadyfn.length; i++ ){
				domReadyfn[i]($_);
			}
		}
		function checkReadyState() {
			if (document.readyState === 'complete') {
				document.detachEvent('onreadystatechange', checkReadyState);
				fireContentLoadedEvent();
			}
		}
		function pollDoScroll() {
		    try { document.documentElement.doScroll('left'); }
		    catch(e) {
		      timer = defer(pollDoScroll);
		      return;
		    }
		    fireContentLoadedEvent();
		}
		domReadyfn.push(callback);
		if( document.addEventListener){
			document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
			window.addEventListener('load', fireContentLoadedEvent);
		} else {
			document.attachEvent('onreadystatechange', checkReadyState);
			if (window == top)
				timer = defer(pollDoScroll);
			window.attachEvent('onload', fireContentLoadedEvent);
		}
	}
	$_.O.extend($_.Utils, {
		makeuid : makeuid,
		ready: ready
	});
})(Asdf);(function ($_) {
	$_.Base = {};
	function subclass() {};
	var Class = function(/*parent, protoProps, staticProps*/) {
		var arg = $_.A.toArray(arguments), parent = null, protoProps, staticProps;
		if($_.O.isFunction(arg[0]))
			parent = arg.shift();
		protoProps = arg[0];
		staticProps = arg[1];
		function child() {
			var self = this, key, arg = $_.A.toArray(arguments);
			for(key in self){
				if(!$_.O.isFunction(self[key]))self[key] = $_.O.clone(self[key]); 
			}
			function initsuper(parent) {
				if(!parent) return;
				if(parent.superclass)
					initsuper(parent.superclass);
				parent.prototype.initialize.apply(self, arg);
			}
			initsuper(parent);
			this.initialize.apply(this, arg);
		}
		child.superclass = parent;
		child.subclasses = [];
		if(parent){	
			subclass.prototype = parent.prototype;
			child.prototype = new subclass();
			parent.subclasses.push(child);
		}
		child.prototype.initialize = function () {};
		if (protoProps)
			$_.O.extend(child.prototype, protoProps);
		if (staticProps)
			$_.O.extend(child, staticProps);
		child.extend = $_.F.wrap($_.O.extend, function (fn, obj){
			var extended = obj.extended;
			fn(child, obj);
			if(extended) extended(child);
		});
		child.include = $_.F.wrap($_.O.extend, function (fn, obj){
			var included = obj.included;
			fn(child.prototype, obj);
			if(included) included(child);
		});
		child.prototype.constructor = child;
		return child;
	};

	$_.O.extend($_.Base, {
		Class: Class
	});
})(Asdf);(function ($_) {
	$_.Template = {};
	var attrBind = function(element, attrs) {
		var hasAttribute =  function (node, attr) {
			if (node.hasAttribute)
				return node.hasAttribute(attr);
			else
				return node.getAttribute(attr);
		};
		for(key in attrs){
			if(key.toLowerCase() === 'html'){
				htmlBind(element,attrs[key]);
			}
			else if(hasAttribute(element, key)) {
				element.setAttribute(key,attrs[key]);
			}
		}
	}
	,textBind = function(element, text) {
		element.innerHTML = '';
		element.appendChild(document.createTextNode(text));
	}
	,htmlBind = function(element, html) {
		element.innerHTML = html;
	}
	,findElement = function(root,id) {
		var element;
		if(root.id === id){
			return root;
		}
		function find(element, id) {
			var children = element.childNodes, i, res;
			var length = children.length;
			for(i=0; i<length; i++) {
				if(children[i].nodeType !== 1) continue;
				else if(children[i].id === id){
					return children[i];
				}
				else if(children[i].childNodes.length > 0){
					res = find(children[i],id);
					if(res) {
						return res;
					}
				}
			}
			return null;
		}
		try{
			element = root.querySelectorAll('#'+id)[0]; 
			return element;
		}catch (e){
			console.log('d');
			return find(root,id);
		}
	}
	,bind = function(element, obj) {
		var key, target;
		var valiableNodeType = element.nodeType === 1 || element.nodeType === 11;
		// validate
		if (!valiableNodeType) return null;
		if (obj.toString() !== '[object Object]' ) return null;
		for (key in obj){
			target = findElement(element, key);
			if(!target) continue;
			if(typeof obj[key] === 'string') {
				textBind(target, obj[key]);
			}
			else if(obj[key].toString() === '[object Object]'){
				attrBind(target, obj[key]);
			}
		}
		return element;
		
	};
	$_.Template.bind = bind;
})(Asdf);(function (definition) {
    // RequireJS
    if (typeof define == "function") {
        define(definition);
    } else {
        definition();
    }
})(function() {
	window.le = {};
});(function (le, $_) {
	var Class = $_.Base.Class;
	function get(key) {
		return this._attributes[key];
	}
	function has(key){
		return get(key) != null;
	}
	function set(key, value, callback) {
		var error = this.validate(key, value);
		if(error){
			this._attributes[key] = value;
		}
		if(callback) callback(error, key, value);
	}
	function validate(key, value){
		if(!this._validator[key]) return true;
		var error = this._validator[key](value);
		if(error === undefined) return true;
		return error;
	}
	function addValidate(key, fn) {
		this._validator[key] = fn;
	}
	function removeValidate(key, fn){
		delete this._validate[key];
	}
	function fetch(callback) {
		
	}
	function save(callback) {
		
	}
	function keys(callback) {
		return $_.O.keys(_attributes);
	}
	function initialize(attr, validator) {
		if(attr){
			this._attributes = $_.O.clone(attr);
		}
		if(validator){
			this._validator = validator;
		}
	}
	var Model = Class({
		_attributes: {},
		_validator: {},
		_url: '',
		get:get,
		set: set,
		has: has,
		validate:validate,
		keys: keys,
		fetch: fetch,
		save: save,
		initialize: initialize
	});
	le.Model = Model;
})(le, Asdf);(function (le, $_) {
	var Class = $_.Base.Class, extend = $_.O.extend ;
	viewHelper = {
		removeAllEvent : function(element, key) {
			$_.Event.removeAll(element, key);
		},
		addEvents : function(element, events) {
			var key;
			for (key in events) {
				var method = events[key];
				if (!$_.O.isFunction(method))
					throw new TypeError("event handler Error.");
				method = $_.F.bind(method, self);
				$_.Event.on(element, key, method);
			}
		},
		empty : function(element) {
			element.innerHTML = '';
			viewHelper.removeAllEvent(element);
		},
		domBind : function(element, el, strings) {
			if ($_.O.isString(el)) {
				el = $_.S.toDocumentFragment(el);
			}
			if (el.nodeType === 1 || el.nodeType === 9 || el.nodeType === 11)
				element.appendChild($_.Template.bind(el, strings));
		},
		render : function(element) {
			var parentElement;
			parentElement = self.parentElement;
			if ($_.O.isString(self.parentElement)) {
				parentElement = document.getElementById(self.parentElement);
			}
			if (!element.parentNode || element.parentNode !== parentElement) {
				parentElement = parentElement || document.body;
				parentElement.appendChild(element);
			}
		}
	};
	function render(data, callback) {
		var clone = $_.O.clone;
		var strings = clone(this.getStrings()), html = this.getHtml(), events = clone(this.getEvents());
		extend(strings, data&&data.strings);
		extend(events, data&&data.events);
		if($_.O.isFunction(callback)){
			callback(this.element, {strings: strings, html: html, events:events});
		} else {
			this.element.empty();
			this.element.domBind(html, strings);
			this.element.addEvents(events);
			this.element.render();
		}
	}
	
	function getHtml() {
		var mode = this.conf[this.mode], html;
		if(mode && (html = mode.html ) ) {
			return html;
		}
		return this.conf['default'].html;
	}
	function setHtml(id, html) {
		var mode = this.conf[this.mode];
		if(mode) {
			mode.html = html;
		}
		throw new Error('default can\'t setting');
	}
	
	function getEvents() {
		var mode = this.conf[this.mode], events;
		if(mode && (events = mode.events))
			return events;
		return this.conf['default'].events;
	}
	function setEvents(events) {
		var mode = this.conf[this.mode];
		if(mode) {
			if(mode.events) mode.events = {};
			extend (mode.events, events);
		}
		throw new Error('default can\'t setting');
	}	
	
	function getStrings() {
		var mode = this.conf[this.mode], strings;
		if(mode && (strings = mode.strings))
			return strings;
		return this.conf['default'].strings;
	}
	function setStrings(string){
		var mode = this.conf[this.mode];
		if(mode) {
			if(mode.strings) mode.strings = {};
			extend (mode.strings, string);
		}
		throw new Error('default can\'t setting');
	}
	
	function setVM(vm) {
		this.vm = vm;
		vm.view = this;
	}
	function changeMode(mode) {
		this.mode = mode;
	}
	function initialize(options) {
		var self = this, methodize = $_.F.methodize;
		function make(obj) {
			if(!(obj && obj.tagName)) return null;
			var key, el = document.createElement(obj.tagName);
			if(el.className)el.className = obj.className;
			if (obj.attr) {
				for(key in obj.attr){
					 el.setAttribute(key, obj.attr[key]);
				}
			}
			return el;
		}
		function configure(options) {
			if(options.element){
				if($_.O.isElement(options.element)){
					self.element = options.element;
				}else {
					self.element = make(options.element);
				}
			}
			
			$_.A.each({
				removeAllEvent : function(element, key) {
					$_.Event.removeAll(element, key);
				},
				addEvents : function(element, events) {
					var key;
					for (key in events) {
						var method = events[key];
						if (!$_.O.isFunction(method))
							throw new TypeError("event handler Error.");
						method = $_.F.bind(method, self);
						$_.Event.on(element, key, method);
					}
				},
				empty : function(element) {
					element.innerHTML = '';
					viewHelper.removeAllEvent(element);
				},
				domBind : function(element, el, strings) {
					if ($_.O.isString(el)) {
						el = $_.S.toDocumentFragment(el);
					}
					if (el.nodeType === 1 || el.nodeType === 9 || el.nodeType === 11)
						element.appendChild($_.Template.bind(el, strings));
				},
				render : function(element) {
					var parentElement;
					parentElement = self.parentElement;
					if ($_.O.isString(self.parentElement)) {
						parentElement = document.getElementById(self.parentElement);
					}
					if (!element.parentNode || element.parentNode !== parentElement) {
						parentElement = parentElement || document.body;
						parentElement.appendChild(element);
					}
				}
			}, function (value, key){
				self.element[key] = methodize(value);
			});
			
			if(options.parentElement){
				self.parentElement = options.parentElement;
			}
			if(options.vm){
				self.setVM(options.vm);
			}
			if(options.conf) {
				extend(self.conf, options.conf, true);
			}
		}
		this.element = document.createElement('div');
		if(options === void 0) return;
		configure(options);
	}
	
	var View = Class( {
		conf: {
			'default' : {
				html: '',
				events: {},
				strings: {}
			}
		},
		mode: 'default',
		vm: null,
		element: null,
		parentElement: null,
		render: render,
		setVM: setVM,
		changeMode: changeMode,
		getHtml: getHtml,
		setHtml: setHtml,
		getEvents: getEvents,
		setEvents: setEvents,
		getStrings: getStrings,
		setStrigns: setStrings,
		setVM: setVM,
		initialize: initialize
	});
	le.View = View;
})(le, Asdf);(function (le, $_) {
	var Class = $_.Base.Class;
	function on(eventName, listener){
		if(!$_.O.isString(eventName))
			return null;
		if(!$_.O.isFunction(listener))
			return null;
		if(this.event[eventName] === void 0)
			this.event[eventName] = [];
		this.event[eventName].push($_.F.bind(listener, this));
	}
	function once(eventName, listener){
		tfn = $_.F.wrap(listener, function(fn){
			var arg = [].slice.call(arguments, 1);
			ofn.apply(this, arg);
			remove(eventName, tfn);
		});
		this.on(eventName, tfn);
	}
	function remove(eventName, listener){
		$_.A.without(this.event[eventName], listener);
	} 
	function removeAll(eventName){
		this.event[eventName].length = 0;
	}
	function listeners(eventName){
		return this.event[eventName];
	}
	function emit(eventName, data){
		this.doFilter();
		var runable = this.event[eventName], i;
		for(i = 0; runable&&i < runable.length; i++){
			runable[i](data);
		}
	}
	function addFilter(filter){
		this.filters.push(filter);
	}
	function removeFilter(filter){
		this.filters = $_.A.without(this.filters, filter);
	}
	function doFilter() {
		var i;
		for(i = 0 ; i < this.filters.length; i++ ){
			this.filters[i].call(this,this);
		}
	}
	var EventEmitter = Class({
		initialize: function () {
			this.event = {any: []};
			this.filters = [];
		},
		event:null,
		filters: null,
		on: on,
		once: once,
		remove: remove,
		removeAll: removeAll,
		listeners: listeners,
		emit:emit,
		addFilter: addFilter,
		removeFilter: removeFilter,
		doFilter:doFilter
	});
	le.EventEmitter = EventEmitter;
})(le, Asdf);(function (le, $_) {
	var Class = $_.Base.Class, wrap = $_.F.wrap;
	
	function getVmById(id){
		var children  = this.children, i, finded;
		if(this.id === id) return this;
		else {
			for(i = 0; i < children.length; i++) {
				if(finded = children[i].getVmById(id)) return finded;
			}
		}
		return null;
	}
	function getRoot() {
		var vm = this;
		while(vm = vm.parent, vm.parent);
		return vm;
	}
	
	function notify(){
		var i, data, fn;
		var arg = $_.A.toArray(arguments);
		if($_.O.isPlainObject(arg[0]))
			data = arg.shift();
		if($_.O.isFunction(arg[0]))
			fn = arg.shift();
		
		this.view.render(data, fn);
		for(i = 0; i < this.children.length; i++ ){
			this.children[i].notify.apply(this.children[i], arg);
		}
	}
	
	function getData(key) {
		return this.model.get(key);
	}
	function setData(key, value){
		this.model.set(key, value);
	}
	
	function appendChild(child) {
		child.parent = this;
		this.children.push(child);
	}
	function removeChild(child) {
		this.children = $_.A.without(this.children, child);
	}
	
	function setModel(model) {
		this.model = model;
	}
	function setView(view) {
		this.view = view;
		view.vm = this;
	}
	
	function initialize(options){
		var self= this;
		this.id = "c"+$_.Utils.makeuid();
		if(!options) return;
		if(options.id)this.id = options.id;
		if(options.view) this.setView(options.view);
		if(options.filters) {
			$_.A.each(options.filters, function (method, name){
				self.addFilter(method);
			});
		}
		if(options.model) this.setModel(model);		
		else if(options.data){ this.setModel(new le.Model(options.data));}
		else this.setModel(new le.Model());
	}
	var extendmethod = {};
	$_.A.each($_.A, function(method, name ) {
		extendmethod[name] = wrap(method, function(fn){
			return this.children = fn.apply(this, [this.children].concat([].slice.call(arguments, 1)));
		}
	);
	});
	
	var VM = Class(le.EventEmitter, {
		id: null,
		initialize: initialize,
		view: null,
		parent: null,
		children: [],
		getVmById:getVmById,
		notify: notify,
		getData: getData,
		setData: setData,
		setModel: setModel,
		setView: setView,
		getRoot: getRoot,
		appendChild: appendChild,
		removeChild: removeChild
	});
	VM.include(extendmethod);
	le.VM = VM;
})(le, Asdf);